import { App } from 'antd';
import { Dispatch, ReactNode, SetStateAction, useCallback, useState, useMemo } from 'react';
import { createContext } from 'use-context-selector';

import appService from '@/api/services/appService';
import orchestrationService from '@/api/services/orchestrationService';
import versionService from '@/api/services/versionService';
import { UpdateAppV2Req } from '@/common';
import { AppWorkbenchType, defaultApp } from '@/common/app/constants';
import { useConfirm } from '@/hooks/use-confirm';
import { useRequest2 } from '@/hooks/use-request';
import { t } from '@/locales/i18n';
import { useParams, useRouter } from '@/router/hooks';
import { useOrchestrationStore } from '@/store/orchestrationStore';
import { AppUpdateParams, PostPublishAppProps } from '@/types/app/api';
import { AppChatConfigType, AppDetailType } from '@/types/app/type';
import { StoreEdgeItemType } from '@/types/workflow/edge';
import { StoreNodeItemType } from '@/types/workflow/node';

export enum TabEnum {
  'appEdit' = 'appEdit',
  'permission' = 'permission',
  'knowledge' = 'knowledge',
  'reporte' = 'reporte',
  'preview' = 'preview',
  'test' = 'app-test',
  'share' = 'share',
}

type AppContextType = {
  appId: string;
  preview: boolean;
  currentTab: TabEnum;
  from: string;
  route2Tab: (currentTab: TabEnum) => void;
  appDetail: AppDetailType;
  setAppDetail: Dispatch<SetStateAction<AppDetailType>>;
  loadingApp: boolean;
  updateAppDetail: (data: AppUpdateParams) => Promise<void>;
  onOpenInfoEdit: () => void;
  onOpenTeamTagModal: () => void;
  onDelApp: () => void;
  onSaveApp: (data: PostPublishAppProps) => Promise<void>;
  appLatestVersion:
    | {
        nodes: StoreNodeItemType[];
        edges: StoreEdgeItemType[];
        chatConfig: AppChatConfigType;
      }
    | undefined;
  reloadAppLatestVersion: () => void;
  reloadApp: () => void;
};

export const AppContext = createContext<AppContextType>({
  appId: '',
  preview: false,
  currentTab: TabEnum.appEdit,
  from: '',
  route2Tab(_currentTab: TabEnum): void {
    throw new Error('Function not implemented.');
  },
  appDetail: defaultApp,
  loadingApp: false,
  updateAppDetail(_data: AppUpdateParams): Promise<void> {
    throw new Error('Function not implemented.');
  },
  setAppDetail(_value: SetStateAction<AppDetailType>): void {
    throw new Error('Function not implemented.');
  },
  onOpenInfoEdit(): void {
    throw new Error('Function not implemented.');
  },
  onOpenTeamTagModal(): void {
    throw new Error('Function not implemented.');
  },
  onDelApp(): void {
    throw new Error('Function not implemented.');
  },
  onSaveApp(_data: PostPublishAppProps): Promise<void> {
    throw new Error('Function not implemented.');
  },
  appLatestVersion: undefined,
  reloadAppLatestVersion(): void {
    throw new Error('Function not implemented.');
  },
  reloadApp(): void {
    throw new Error('Function not implemented.');
  },
});

function AppContextProvider({ children }: { children: ReactNode }) {
  const router = useRouter();
  const { message } = App.useApp();
  const {
    appId = '',
    currentTab = TabEnum.appEdit,
    from,
  } = useParams() as {
    appId: string;
    currentTab: TabEnum;
    from: string;
  };
  const preview = currentTab === TabEnum.preview;
  const [isOpenInfoEdit, setIsOpenInfoEdit] = useState(false);

  const onOpenInfoEdit = useCallback(() => {
    setIsOpenInfoEdit(true);
  }, []);

  const onCloseInfoEdit = useCallback(() => {
    setIsOpenInfoEdit(false);
  }, []);

  const {
    setAppLogo,
    setSceneImage,
    setAppDescription,
    setAppName,
    setAppDetail: setFlowAppDetail,
    sceneImage,
    setUserRole,
  } = useOrchestrationStore();

  const route2Tab = useCallback(
    (currentTab: `${TabEnum}`) => {
      console.log(currentTab);
      router.push(`/app/workflow?appId=${appId}&currentTab=${currentTab}`);
    },
    [router, appId],
  );

  const [appDetail, setAppDetail] = useState<AppDetailType>(defaultApp);
  const { loading: loadingApp, runAsync: reloadApp } = useRequest2<UpdateAppV2Req, []>(
    () => {
      if (appId) {
        return orchestrationService
          .getAppDetailV2(appId, AppWorkbenchType.manage)
          .then((res) => res);
      }
      return Promise.reject(new Error('Not load app'));
    },
    {
      manual: false,
      refreshDeps: [appId],
      onError(_err: any) {
        router.replace('/worklayouts');
      },
      onSuccess(res) {
        setAppDetail(res.workflow || defaultApp);
        setFlowAppDetail(res);
        setUserRole(res.roles_for_user_in_app || []);
      },
    },
  );

  const { data: appLatestVersion, run: reloadAppLatestVersion } = useRequest2(
    () => versionService.getAppLatestVersion(appId),
    {
      manual: false,
    },
  );

  const { runAsync: updateAppDetail } = useRequest2(async (data: AppUpdateParams) => {
    await appService.putAppById(appId, data);
    setAppDetail((state) => ({
      ...state,
      ...data,
      modules: data.nodes || state.modules,
    }));
  });

  const { runAsync: onSaveApp } = useRequest2(async (data: PostPublishAppProps) => {
    await versionService.postPublishApp(appId, data);
    setAppDetail((state) => ({
      ...state,
      ...data,
      modules: data.nodes || state.modules,
    }));
    reloadAppLatestVersion();
  });

  const { openConfirm: openConfirmDel, ConfirmModal: ConfirmDelModal } = useConfirm({
    content: t('confirm_del_app_tip', { name: appDetail.name }),
    type: 'delete',
  });
  const { runAsync: deleteApp } = useRequest2(
    async () => {
      if (!appDetail) return Promise.reject(new Error('Not load app'));
      return appService.delAppById(appDetail.id);
    },
    {
      onSuccess() {
        router.replace(`/worklayouts`);
      },
      successToast: t('common.Delete Success'),
      errorToast: t('common.Delete Failed'),
    },
  );

  const onDelApp = useCallback(
    () =>
      openConfirmDel(deleteApp, undefined, t('confirm_del_app_tip', { name: appDetail.name }))(),
    [appDetail.name, deleteApp, openConfirmDel],
  );

  const onOpenTeamTagModal = () => {};

  const { runAsync: saveSubmitSuccess } = useRequest2(
    async (data: {
      appName: string;
      appDescription: string;
      appLogo: string;
      sceneImage: string;
      appLogoList: string[];
      sceneImageList: string[];
    }) => {
      setAppLogo(data.appLogo);
      setSceneImage(data.sceneImage);
      setAppDescription(data.appDescription);
      setAppName(data.appName);
      orchestrationService.updateAppImage(appId, {
        logo: data.appLogoList,
        scene: data.sceneImageList,
      });
      await updateAppDetail({
        name: data.appName,
        avatar: data.appLogo,
        intro: data.appDescription,
      });
      await appService.postUpdateAppInfo(appId, {
        app_name: data.appName,
        app_logo: data.appLogo,
        app_description: data.appDescription,
        scene_image: data.sceneImage,
      });
    },
    {
      onSuccess() {
        message.success(t('common.Update Success'));
        reloadApp();
        onCloseInfoEdit();
      },
      errorToast: t('common.Update Failed'),
    },
  );

  const contextValue: AppContextType = useMemo(
    () => ({
      appId,
      preview,
      currentTab,
      from,
      route2Tab,
      appDetail,
      setAppDetail,
      loadingApp,
      updateAppDetail,
      onOpenInfoEdit,
      onOpenTeamTagModal,
      onDelApp,
      onSaveApp,
      appLatestVersion,
      reloadAppLatestVersion,
      reloadApp,
    }),
    [
      appId,
      preview,
      currentTab,
      from,
      route2Tab,
      appDetail,
      loadingApp,
      updateAppDetail,
      onOpenInfoEdit,
      onDelApp,
      onSaveApp,
      appLatestVersion,
      reloadAppLatestVersion,
      reloadApp,
    ],
  );

  return <AppContext.Provider value={contextValue}>{children}</AppContext.Provider>;
}

export default AppContextProvider;
